package com.example.a05;

import org.mybatis.spring.mapper.MapperFactoryBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;

import java.io.IOException;

public class MapperPostProcessor implements BeanDefinitionRegistryPostProcessor {

    /**
     * 主要用于扫描指定包下的接口，并将其作为MyBatis映射器注册到Spring容器中
     *
     * @param beanFactory Bean定义工厂，用于注册Bean定义
     * @throws BeansException 如果Bean处理过程中发生错误
     */
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
        try {
            // 创建资源解析器，用于扫描类路径下的类文件
            PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
            // 扫描指定包下的所有类文件
            Resource[] resources = resolver.getResources("classpath:com/example/a05/mapper/**/*.class");

            // 创建Bean名称生成器
            AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
            // 创建缓存元数据读取工厂，用于读取类的元数据
            CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();

            // 遍历扫描到的类文件资源
            for (Resource resource : resources) {
                // 读取资源的元数据
                MetadataReader reader = factory.getMetadataReader(resource);
                // 获取类元数据
                ClassMetadata classMetadata = reader.getClassMetadata();
                // 检查是否为接口，因为MyBatis映射器通常定义为接口
                if (classMetadata.isInterface()) {
                    // 创建MapperFactoryBean的Bean定义，设置映射器接口的类名
                    AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class)
                            .addConstructorArgValue(classMetadata.getClassName())
                            .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE) // 按类型装配
                            .getBeanDefinition();

                    // 创建映射器接口类的Bean定义
                    AbstractBeanDefinition beanDefinition2 = BeanDefinitionBuilder.genericBeanDefinition(classMetadata.getClassName()).getBeanDefinition();


                    // 生成Bean的名称
                    String beanName = generator.generateBeanName(beanDefinition2, beanFactory);
                    // 将映射器Bean定义注册到Spring容器中
                    beanFactory.registerBeanDefinition(beanName, beanDefinition);
                }

            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }
}
